package com.kc.common.utils;


import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.google.gson.Gson;

import com.kc.common.config.TicketConfig;
import com.kc.common.model.KcTicketResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.*;

@Slf4j
@Component
public class TicketUtil {
    @Resource
    private TicketConfig ticketConfig;
    @Resource
    private RestTemplate restTemplate;
    /**
     * 往猴子系统发送数据，获取请求
     * @param url
     * @param param
     * @return
     */
    public KcTicketResult requestTicket(String url, String param){
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.add("Accept-Charset", "utf-8");
        HttpEntity<String> request = new HttpEntity<>(param, headers);
        log.info("请求票务系统url{}",url);
        log.info("请求票务系统参数{}",param);
        ResponseEntity<String> postForEntity = restTemplate.postForEntity(url, request, String.class);
        KcTicketResult kcTicketResult = new KcTicketResult();
        try{
            kcTicketResult = JSONObject.parseObject(postForEntity.getBody(), new TypeReference<KcTicketResult>() {
            });

        }catch (Exception e){
            log.info("[票务管理]请求票务系统返回数据:{}",postForEntity);
            //throw new CustomizeException(ReturnMessageEnum.GET_TICKET_INFO_ERROR.getMessage());
            return null;
        }
        if(kcTicketResult.getErrorCode() != 0){
            return null;
        }
        return kcTicketResult;
    }
    /**
     * 获取发送猴子系统的最终字符串参数
     * @return
     */
    public String getRaramString(Map<String,String> param){
        //排序后参数
        Map<String,String> ascParam = this.ascMap(param);
        //排序后map转字符串
        String str = this.mapToString(ascParam);
        //Encrypt加密
        String sign = this.getEncryptSign(str);
        //到猴子系统的参数
        String requestParamStr = this.getRequestParam(sign,param);
        return requestParamStr;
    }

    /**
     * 获取encrypt加密后的验签值
     * @param str
     * @return
     */
    public String getEncryptSign(String str){
        byte[] key = ticketConfig.getAppSct().getBytes();
        //构建
        SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.DES, key);
        //加密
        byte[] encrypt = aes.encrypt(str);
        //解密
        byte[] decrypt = aes.decrypt(encrypt);
        //加密为16进制表示
        String encryptHex = aes.encryptHex(str);
        //解密为字符串
        //String decryptStr = aes.decryptStr(encryptHex, CharsetUtil.CHARSET_UTF_8);
        String sign = encryptHex.toUpperCase();
        return sign;
    }
    /**
     * 获取需要到猴子系统的JSON参数
     * @param sign
     * @param param
     * @return
     */
    public String getRequestParam(String sign,Map<String,String> param){
        Map<String,Object> map = new HashMap<>();
        map.put("AgreeNo",ticketConfig.getAppNo());
        map.put("Sign",sign);
        map.put("Data",param);
        Gson g = new Gson();
        String str = g.toJson(map);
        return str;
    }
    /**
     * map参数转换成需要验签的字符串
     * @param map
     * @return
     */
    private String mapToString(Map<String,String> map){
        String str = "&";
        for(Map.Entry<String, String> entry : map.entrySet()){
            String mapKey = entry.getKey();
            String mapValue = entry.getValue();
            if(mapValue == null || mapValue.equals("")){
                continue;
            }
            str = str+mapKey+"="+mapValue+"&";
        }
        if(str.equals("&")){
            str = "&&";
        }
        str = ticketConfig.getAppId()+str+ticketConfig.getAppId();
        log.info("[sign值生成]原值字符串{}",str);
        return str;
    }
    /**
     * 实体转map(票务订单使用)
     * @param className
     * @return
     */
    public  Map<String, String> classToMap(Object className) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Field[] fields = className.getClass().getDeclaredFields();
        Map<String,String> map = new HashMap<>();
        for(int i = 0,len = fields.length;i < len;i++){
            String name = fields[i].getName();
            if(name.equals("isOwn") || name.equals("priceName")){
                continue;
            }
            //属性首字母大写
            name = name.substring(0,1).toUpperCase() + name.substring(1);
            //获取属性值的类型
            String type = fields[i].getGenericType().toString();
            //获取属性值
            Method m = className.getClass().getMethod("get" + name);
            if(name.equals("IdCard")){
                name = name.substring(0,2).toUpperCase() + name.substring(2);
            }
            if (type.equals("class java.lang.Integer")) {
                //数字
                Integer value = (Integer)m.invoke(className);
                if(value != null) {
                    map.put(name, value.toString());
                }
            }else if (type.equals("class java.lang.String")){
                //字符串
                String value = (String)m.invoke(className);
                if(value != null) {
                    map.put(name, value);
                }
            }else if (type.equals("class java.lang.Double")){
                //字符串
                String value = (String)m.invoke(className);
                if(value != null) {
                    map.put(name, value);
                }
            }
        }
        return map;
    }

    /**
     * 对MAP按键值升序排序
     * @param param
     * @return
     */
    public  Map<String,String> ascMap(Map<String,String> param){
        Map<String,String> map = new TreeMap<String, String>(
                new Comparator<String>() {
                    public int compare(String obj1, String obj2) {
                        // 降序排序
                        return obj1.compareTo(obj2);
                    }
                });
        for(Map.Entry<String, String> entry : param.entrySet()){
            String mapKey = entry.getKey();
            String mapValue = entry.getValue();
            map.put(mapKey,mapValue);
        }
        return map;
    }
}
